﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
//
using System.Runtime.InteropServices;
//
/*
Copyright 2010 Mirosław M. Mączka

This file is part of Flac2Wma.

    Flac2Wma is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/
namespace Flac2Wma
{
    public partial class Form1 : Form
    {
#if !DEBUG
#error Kompilować jako DEBUG, x86. Inaczej libFlac ma problemy
#endif
        //
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int AnimateWindow(IntPtr hwand, int dwTime, int dwFlags);
        //
        public enum AnimateWindowFlags
        {
            AW_HOR_POSITIVE = 0x00000001,
            AW_HOR_NEGATIVE = 0x00000002,
            AW_VER_POSITIVE = 0x00000004,
            AW_VER_NEGATIVE = 0x00000008,
            AW_CENTER = 0x00000010,
            AW_HIDE = 0x00010000,
            AW_ACTIVATE = 0x00020000,
            AW_SLIDE = 0x00040000,
            AW_BLEND = 0x00080000
        }
        //
        public static string AAC_Encoder { get; set; }
        public static string AAC_CommandLine { get; set; }
        //
        public static string MP3_Encoder { get; set; }
        public static string MP3_CommandLine { get; set; }
        //
        //
        Form4 f4 = null;
        //
        public static string StartDirectory = @"D:\";
        //
        Log l = null;
        //
        public static MI_connector mi = null;
        //
        Form99 f99 = null;// teksty
        //
        public Form1()
        {
            InitializeComponent();
            //
            string[] cmdArgs = Environment.GetCommandLineArgs();
            string s = Environment.CommandLine;
            if (2 == cmdArgs.GetLength(0))
            {
                string targetDir = cmdArgs[1];
                if (!Directory.Exists(targetDir))//zapewne to plik
                {
                    targetDir = Path.GetDirectoryName(targetDir);
                }
                if (Directory.Exists(targetDir))
                {
                    StartDirectory = targetDir;
                    LoadTree(StartDirectory);
                }
            }
            //
            defaultSettings();
            //treeView1.CheckBoxes = true;
            //
            f4 = new Form4();
            //
            mi = new MI_connector();
            //
            f99 = new Form99();
            //
        }
        public void LoadTree(string root)
        {
            //http://msdn.microsoft.com/en-us/library/bb513869.aspx
            // Data structure to hold names of subfolders to be examined for files.
            //
            Stack<string> dirs = new Stack<string>(200);
            Stack<TreeNode> tns = new Stack<TreeNode>(200);
            //
            if (!Directory.Exists(root))
            {
                //throw new ArgumentException();
                return;
            }
            //
            treeView1.Enabled = true;
            treeView1.Nodes.Clear();
            //
            dirs.Push(root);
            tns.Push(treeView1.Nodes.Add(root, "[" + Path.GetFileNameWithoutExtension(root) + "]"));
            try
            {
                treeView1.Nodes[root].Checked = (0 != Directory.GetFiles(root, "*.flac").Count());
            }
            catch
            {
                treeView1.Nodes[root].Checked = false;
            }
            //
            treeView1.Enabled = false;
            treeView1.UseWaitCursor = true;
            //
            while (dirs.Count > 0)
            {
                string currentDir = "";
                currentDir = dirs.Pop();
                TreeNode tn = tns.Pop();
                //
                string[] subDirs;
                try
                {
                    subDirs = Directory.GetDirectories(currentDir);
                }
                catch
                {
                    continue;
                }
                //
                // Push the subdirectories onto the stack for traversal.
                // This could also be done before handing the files.
                int flacCount = 0;
                //int subDirCount = 0;
                TreeNode _tn = null;
                foreach (string str in subDirs)
                {
                    dirs.Push(str);
                    //
                    //subDirCount = Directory.GetDirectories(str, "*").Count();
                    flacCount = Directory.GetFiles(str, "*.flac").Count();
                    //
                    //if (0 == subDirCount && 0 == flacCount) continue;
                    _tn = tn.Nodes.Add(str, Path.GetFileName(str));
                    _tn.Checked = (0 != flacCount);
                    tns.Push(_tn);
                    //
                    //
                }
            }
            //
            CleanTreeView.WalkTree(treeView1.Nodes);
            //
#if false
            if (0 == treeView1.Nodes[0].GetNodeCount(false) && !treeView1.Nodes[0].Checked)
            {
                treeView1.Enabled = false;
            }
            else
            {
                treeView1.Enabled = true;
            }
#endif
            //
            treeView1.Enabled = true;// musi być, jeżeli DRAGDROP ma działać
            treeView1.ExpandAll();
            treeView1.UseWaitCursor = false;
            //
            return;
        }
        private IOutputHandler hOut = null;
        private int Do(string fileFlac)
        {
            int iRetval = 0;
            //
            string tmpFile = Path.GetTempPath();
            //
            if (System.IO.File.Exists(fileFlac))
            {
                System.IO.FileAttributes fa = System.IO.File.GetAttributes(fileFlac);
                fa = fa & ~System.IO.FileAttributes.ReadOnly;
                System.IO.File.SetAttributes(fileFlac, fa);
            }
            //
            f4.Clear();
            f4.SetTitle("...");
            //f4.AnimShow();
            f4.Show();
            //
            f4.SetText(Path.GetFileName(fileFlac));
            l.AddTitle("Input file: [" + fileFlac + "]");// start
            //
            Handler_Tag hat = new Handler_Tag();
            //
            l.AddEntry(1, "[TAG]"); 
            f4.Set(0, hat.Do(fileFlac));
            //
            f4.SetTitle(hat.Album);
            //
            if ("" != hat.ErrorMessage)
            {
                l.AddEntry(2, "ERROR: " + hat.ErrorMessage); 
            }
            if (hat.NoMetadata)
            {
                l.AddEntry(2, "File without metadata!");
            }
            //
            Handler_Flac haf = new Handler_Flac();
            //haf.Flac_Exe_PathName = Path.Combine(Application.StartupPath, @"Flac2Wav.exe");
            //
            l.AddEntry(1, "[FLAC->WAV]");
            if(haf.Do(fileFlac, tmpFile, false))
            {
                f4.Set(1, true);
            }
            else
            {
                f4.Set(1, false);
                if (haf.InvalidFormat)
                {
                    l.AddEntry(2, "ERROR: invalid format");
                    l.AddEntry(2, haf.ErrorMessage);
                    l.AddEntry(2, "------------------------------------------");
                    f4.Set(2, false);
                    iRetval = 1; goto exit;
                }
                //
                if(haf.Do(fileFlac, tmpFile, true))
                {
                    f4.Set(1, true);
                    l.AddEntry(2, "WARNING: Invalid Md5 Signature");
                }
                else
                {
                    l.AddEntry(2, "ERROR: " + haf.ErrorMessage);
                    iRetval = 1; goto exit;
                }
                //
            }
            //
            if (!haf.IsOtputFileOK())
            {
                if (-1 == haf.PlayTime) l.AddEntry(2, "FLAC: invalid PlayTime for .flac!");
                l.AddEntry(2, "WAV: invalid file!");
                f4.Set(1, false);
                //
                iRetval = 1; goto exit;
            }
            //
            hOut.ClearProps();
            hOut.AlbumTitle = hat.Album;
            hOut.Author = hat.Artist;
            hOut.Description = hat.Description;
            hOut.Genre = hat.Genre;
            hOut.Title = hat.Title;
            //
            int iResult = -1;
            if (Int32.TryParse(hat.TrackNumber, out iResult))
            {
                if (iResult > 0)
                {
                    hOut.TrackNumber = iResult;
                }
            }
            if (Int32.TryParse(hat.Date, out iResult))
            {
                if (iResult > 0)
                {
                    hOut.Year = iResult;
                }
            }            
            hOut.DeleteInputFile = true;
            //
            l.AddEntry(1, "[WAV->" + hOut.OutputFileType + "]");
            f4.Set(2, hOut.Do(haf.FileWavPathName, Path.GetDirectoryName(fileFlac)));
            //
            if ("" != hOut.ErrorMessage)
            {
                l.AddEntry(2, "ERROR: " + hOut.ErrorMessage);
            }
            //
            if (!hOut.IsOtputFileOK(haf.PlayTime))
            {
                l.AddEntry(2, hOut.OutputFileType +  ": invalid file!");
                f4.Set(2, false);
                if (-1 == hOut.PlayTime) l.AddEntry(2, hOut.OutputFileType + ": invalid PlayTime for " + hOut.OutputFileNameExtension + "!");
                if (haf.PlayTime != hOut.PlayTime) l.AddEntry(2, hOut.OutputFileType + ": different PlayTime FLAC={0} != {1}:{2}!", haf.PlayTime / 1000.0, hOut.OutputFileType, hOut.PlayTime / 1000.0);
                //
                iRetval = 1;
            }
            else
            {
                l.AddEntry(2, hOut.OutputFileType + ": OK");
                f4.Set(2, true);
                File.Delete(fileFlac);
                iRetval = 0;
            }
            //
            //
            //
            //
            //
            exit:
            l.AddEntry(1, "[End.]");
            //
            System.Threading.Thread.Sleep(500);
            if (0 != iRetval)
            {
                System.Threading.Thread.Sleep(3000);
            }
            //
            f4.Hide();
            //
            return iRetval;
        }

        private void buttonLoadDirs_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.ShowNewFolderButton = false;
            folderBrowserDialog1.RootFolder = Environment.SpecialFolder.MyComputer;
            folderBrowserDialog1.SelectedPath = StartDirectory;
            if (DialogResult.OK == folderBrowserDialog1.ShowDialog())
            {
                LoadTree(folderBrowserDialog1.SelectedPath);
            }

        }

        private void buttonDo_Click(object sender, EventArgs e)
        {
            //
            this.Enabled = false;
            //
            //
            hOut = null;
            if (wMALosslessToolStripMenuItem.Checked)
            {
                hOut = new Handler_Wma();
            }
            else if (aACToolStripMenuItem.Checked)
            {
                hOut = new Handler_AAC();
            }
            else if (mP3ToolStripMenuItem.Checked)
            {
                hOut = new Handler_MP3();
            }
            //
            if(null == hOut)
            {
                MessageBox.Show("handle is NULL", "Encoder error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                goto finis;
            }
            //
            if(!hOut.IsEncoderOK())
            {
                MessageBox.Show("Encoder not found!", "Encoder error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                System.Diagnostics.Process.Start(hOut.DefaultDownloadPage);
                goto finis;
            }
            //
            //
            //
            treeView1.UseWaitCursor = true;
            //
            DoTree(treeView1.Nodes);
            //
            treeView1.UseWaitCursor = false;
            //treeView1.Enabled = true;
        finis: ;
            this.Enabled = true;
            this.BringToFront();
            //
        }
        public void DoTree(TreeNodeCollection tnRoot)
        {
            // Now find all the subdirectories under this directory.
            for (int n = 0; n < tnRoot.Count; n++)
            {
                //string a = tnRoot[n].Text;
                if (tnRoot[n].Checked)
                {
                    //
                    // pliki w jednym katalogu, jeden plik z logiem
                    l = new Log();
                    //
                    string[] ff = Directory.GetFiles(tnRoot[n].Name, "*.flac");
                    int nErr = 0;
                    foreach (string f in ff)
                    {
                        if (0 != string.Compare(".flac", Path.GetExtension(f), true)) continue;
                        treeView1.Update();
                        Application.DoEvents();
                        nErr += Do(f);
                    }
                    if (0 == nErr)
                    {

                        tnRoot[n].BackColor = Color.Green;
                        tnRoot[n].ForeColor = Color.Yellow;
                    }
                    else
                    {
                        tnRoot[n].BackColor = Color.Red;
                        tnRoot[n].ForeColor = Color.White;
                        //
                        l.Save(tnRoot[n].Name);// tylko, gdy był błąd
                        //
                    }
                    treeView1.Refresh();
                    //
                    //
                    //l.Save(tnRoot[n].Name);// end
                    l = null;
                    //
                    Application.DoEvents();
                }
                DoTree(tnRoot[n].Nodes);
            }
            return;
        }

        private void Form1_VisibleChanged(object sender, EventArgs e)
        {
            if (this.Visible)
            {
                AnimateWindow(this.Handle, 200, (int)(AnimateWindowFlags.AW_BLEND | AnimateWindowFlags.AW_HIDE));
            }
            else
            {
                AnimateWindow(this.Handle, 200, (int)(AnimateWindowFlags.AW_BLEND | AnimateWindowFlags.AW_ACTIVATE));
            }
        }

        private void treeView1_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;
                //
                string targetDir = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
                //
                if (!Directory.Exists(targetDir))//zapewne to plik
                {
                    targetDir = Path.GetDirectoryName(targetDir);
                }
                if (Directory.Exists(targetDir))
                {
                    StartDirectory = targetDir;
                    LoadTree(StartDirectory);
                }
                //
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
            //
        }

        private void treeView1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        private void treeView1_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }
        //
#if false
        private bool chaeckWME()
        {
            if (!File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Windows Media Components\Encoder\Settings\d6_qvbr_100_audio.prx"))
            {
                //
                string url = "http://www.microsoft.com/downloads/details.aspx?FamilyID=5691ba02-e496-465a-bba9-b2f1182cdf24&displaylang=en";
                string url64 = "http://www.microsoft.com/downloads/details.aspx?FamilyId=CC41218D-7E37-4546-BF0B-1276959EE3EF&displaylang=en";
                //
                MessageBox.Show("Brak Windows Media Encoder\nzainstaluj!", "Windows Media Encoder");
                //
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.UseShellExecute = true;
                p.StartInfo.FileName = (4==IntPtr.Size?url:url64);
                p.Start();
                //
                return false;
            }
            return true;
        }
#endif
        private void Form1_Load(object sender, EventArgs e)
        {
        }
        private bool inMenuWork = false;
        private void encoderToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            if (inMenuWork) return;
            inMenuWork = true;
            outputToolStripMenuItem.Enabled = false;
            //
            ToolStripMenuItem mi = sender as ToolStripMenuItem;
            for(int n=0; n<outputToolStripMenuItem.DropDownItems.Count;n++)
            {
                ToolStripMenuItem mi0 = outputToolStripMenuItem.DropDownItems[n] as ToolStripMenuItem;
                if (null == mi0) continue;
                mi0.Checked = false;
            }
            mi.Checked = true;
            //
            outputToolStripMenuItem.Enabled = true; ;
            inMenuWork = false;
        }


        private string default_AAC_Encoder = "neroAacEnc.exe";
        private string default_AAC_CommandLine = "-q 0.62  -if \"{0}\" -of \"{1}\"";
        //
        private string default_MP3_Encoder = "lame.exe";
        private string default_MP3_CommandLine = "-q0 -b320 --id3v2-only --nohist \"{0}\" \"{1}\"";
        //
        private void defaultSettings()
        {
            bool isSave = false;
            //
            AAC_Encoder=Properties.Settings.Default.AAC_Encoder.Trim();
            if(""==AAC_Encoder)
            {
                AAC_Encoder = Properties.Settings.Default.AAC_Encoder = default_AAC_Encoder;
                isSave = true;
            }
            AAC_CommandLine= Properties.Settings.Default.AAC_CommandLine.Trim();
            if ("" == AAC_CommandLine)
            {
                AAC_CommandLine = Properties.Settings.Default.AAC_CommandLine = default_AAC_CommandLine;
                isSave = true;
            }
            //
            MP3_Encoder=Properties.Settings.Default.MP3_Encoder.Trim();
            if ("" == MP3_Encoder)
            {
                MP3_Encoder = Properties.Settings.Default.MP3_Encoder = default_MP3_Encoder;
                isSave = true;
            }
            MP3_CommandLine = Properties.Settings.Default.MP3_CommandLine.Trim();
            if ("" == MP3_CommandLine)
            {
                MP3_CommandLine = Properties.Settings.Default.MP3_CommandLine = default_MP3_CommandLine;
                isSave = true;
            }
            //
            if(isSave)
            {
                Properties.Settings.Default.Save();
            }
            //
        }
        private void saveSettings()
        {
            //
            Properties.Settings.Default.AAC_Encoder = AAC_Encoder;
            Properties.Settings.Default.AAC_CommandLine = AAC_CommandLine;
            Properties.Settings.Default.MP3_Encoder = MP3_Encoder;
            Properties.Settings.Default.MP3_CommandLine = MP3_CommandLine;
            Properties.Settings.Default.Save();
            //
        }

        private void configToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormEncoders fe = new FormEncoders();
            //
            FormEncoders.AAC_Encoder = AAC_Encoder;
            FormEncoders.AAC_CommandLine = AAC_CommandLine;
            //
            FormEncoders.MP3_Encoder = MP3_Encoder;
            FormEncoders.MP3_CommandLine = MP3_CommandLine;
            //
            fe.OnSave += fe_OnSave;
            //
            fe.ShowDialog();
        }

        void fe_OnSave(FormEncoders.SelectEncodersEventArgs e)
        {
            AAC_Encoder = e.AAC_Encoder;
            AAC_CommandLine = e.AAC_CommandLine;
            //
            MP3_Encoder = e.MP3_Encoder;
            MP3_CommandLine = e.MP3_CommandLine;
            //
            saveSettings();
            //
        }

    }//class
}
